import socket
import threading
import time
from typing import Optional, Callable


class TcpClient:
    def __init__(self):
        self._sock: Optional[socket.socket] = None
        self._recv_thread: Optional[threading.Thread] = None
        self._running = False
        self._lock = threading.Lock()

        self._ip: str = '127.0.0.1'
        self._port: int = 9600
        # 自动重连取消
        self._auto_reconnect: bool = False
        self._reconnect_interval_sec: float = 3.0

        # Callbacks set by UI
        self.on_connected: Optional[Callable[[], None]] = None
        self.on_disconnected: Optional[Callable[[], None]] = None
        self.on_received: Optional[Callable[[bytes], None]] = None
        self.on_error: Optional[Callable[[str], None]] = None

    @property
    def connected(self) -> bool:
        return self._sock is not None

    def connect(self, ip: str, port: int, auto_reconnect: bool = False):
        with self._lock:
            self._ip = ip
            self._port = port
            self._auto_reconnect = False
        self._ensure_connect()

    def _ensure_connect(self):
        # Create socket and connect
        try:
            with self._lock:
                if self._sock:
                    return
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                s.settimeout(5)
                s.connect((self._ip, self._port))
                s.settimeout(None)
                self._sock = s
                self._running = True
            if self.on_connected:
                self.on_connected()
            # Start recv thread
            self._recv_thread = threading.Thread(target=self._recv_loop, daemon=True)
            self._recv_thread.start()
        except Exception as e:
            if self.on_error:
                self.on_error(str(e))
            # 不再自动重连

    def _schedule_reconnect(self):
        # 兼容旧调用：不做任何事
        return

    def disconnect(self):
        with self._lock:
            self._auto_reconnect = False
            self._running = False
            if self._sock:
                try:
                    self._sock.shutdown(socket.SHUT_RDWR)
                except Exception:
                    pass
                try:
                    self._sock.close()
                except Exception:
                    pass
            self._sock = None
        if self.on_disconnected:
            self.on_disconnected()

    def send(self, data: bytes) -> None:
        with self._lock:
            s = self._sock
        if not s:
            raise ConnectionError('未连接服务器')
        try:
            s.sendall(data)
        except Exception as e:
            if self.on_error:
                self.on_error(str(e))
            # consider connection broken
            with self._lock:
                try:
                    s.close()
                except Exception:
                    pass
                self._sock = None
                self._running = False
            if self.on_disconnected:
                self.on_disconnected()
            # 不再自动重连

    def _recv_loop(self):
        while True:
            with self._lock:
                s = self._sock
                running = self._running
            if not s or not running:
                return
            try:
                data = s.recv(4096)
                if not data:
                    # peer closed
                    with self._lock:
                        try:
                            s.close()
                        except Exception:
                            pass
                        self._sock = None
                        self._running = False
                    if self.on_disconnected:
                        self.on_disconnected()
                    self._schedule_reconnect()
                    return
                if self.on_received:
                    self.on_received(data)
            except Exception as e:
                if self.on_error:
                    self.on_error(str(e))
                with self._lock:
                    try:
                        s.close()
                    except Exception:
                        pass
                    self._sock = None
                    self._running = False
                if self.on_disconnected:
                    self.on_disconnected()
                # 不再自动重连
                return


